/******************************************************************************
 * Filename : uc_tpool.c
 * Copyright: 
 * Created  : 2011-1-6 by franco.yin
 * Description -
 * 
 ******************************************************************************/

#ifdef __cplusplus
	 extern "C" {
#endif

#include "uc_tpool.h"

static int 
uctp_get_thread_by_id(uctp_main_s *pTpool, int id)
{
	int i = 0;

	for(i=0; i < pTpool->thread_count; i++){
		if(id == pTpool->thread_pool[i].thread_id) {
			return i;
		}
	}

	return ERROR;
}

static void *
uctp_work_thread(void *pThreadPool)
{
	uctp_main_s *pTpool = (uctp_main_s*)pThreadPool;
	pthread_t curid;
	int nseq = 0;
	uctp_thread_s *pThread = NULL;

	curid = pthread_self();
	nseq = uctp_get_thread_by_id(pTpool, curid);
	if(nseq < 0) {
		return NULL;
	}
	pThread = &(pTpool->thread_pool[nseq]);
	uctp_debug("entering working thread [%d]\n", nseq);

	while( TRUE ){
		pthread_mutex_lock(&(pThread->thread_lock));
		pthread_cond_wait(&(pThread->thread_cond), &(pThread->thread_lock));
		pthread_mutex_unlock(&(pThread->thread_lock));		
		uctp_debug("[%d] thread do work!\n", nseq);
		pThread->pJob(pThread->pParam);

		pthread_mutex_lock(&(pThread->thread_lock));		
		pThread->is_busy = 0;
		pthread_mutex_unlock(&(pThread->thread_lock));
		uctp_debug("[%d] do work over\n", nseq);
	}
	return NULL;
}

void *
uctp_creat(int thread_count, int stack_size)
{
	uctp_main_s *pTpool = NULL;
	
	pTpool = (uctp_main_s*)uc_malloc_memset(sizeof(uctp_main_s));	
	if(pTpool == NULL) {
		return NULL;
	}
	
	memset(pTpool, 0, sizeof(uctp_main_s));
	pTpool->thread_count = thread_count;
	pTpool->stacksize = stack_size;
	pthread_attr_init(&(pTpool->th_attr));
	pthread_attr_setdetachstate(&(pTpool->th_attr), PTHREAD_CREATE_DETACHED);
	pthread_attr_setstacksize(&(pTpool->th_attr), pTpool->stacksize);
	pthread_mutex_init(&pTpool->tp_lock, NULL);

	if(pTpool->thread_pool != NULL) {
		uc_free(pTpool->thread_pool);
	}
	pTpool->thread_pool = (uctp_thread_s*)uc_malloc_memset(sizeof(uctp_thread_s) * pTpool->thread_count);

	return (void *)pTpool;
}

int 
uctp_init(void *pThreadPool)
{
	uctp_main_s *pTpool = (uctp_main_s *)pThreadPool;
	uctp_thread_s *pThread = NULL;
	int i = 0;
	int ret = 0;

	if(pTpool == NULL) {
		uctp_err("uctp_init: entry pointer NULL\n");
		return ERROR;
	}

	for(i=0; i < pTpool->thread_count; i++) {
		pThread = &(pTpool->thread_pool[i]);
		pthread_cond_init(&(pThread->thread_cond), NULL);
		pthread_mutex_init(&(pThread->thread_lock), NULL);
		ret = pthread_create(&(pThread->thread_id), &(pTpool->th_attr), uctp_work_thread, pTpool);
		if(ret != 0){
			uctp_err("uctp_init: creat work thread failed\n");
			return ERROR;
		}
		uctp_debug("uctp_init: creat work thread [%d]\n", i);
	}
	return OK;
}

void 
uctp_close(void *pThreadPool)
{
	uctp_main_s *pTpool = (uctp_main_s *)pThreadPool;
	uctp_thread_s *pThread = NULL;
	int i = 0;
	
	if(pTpool == NULL) {
		uctp_err("uctp_close: entry pointer NULL\n");
		return;
	}

	for(i=0; i < pTpool->thread_count; i++){
		pThread = &(pTpool->thread_pool[i]);
		kill(pThread->thread_id, SIGKILL);
		pthread_mutex_destroy(&(pThread->thread_lock));
		pthread_cond_destroy(&(pThread->thread_cond));
		uctp_debug("uctp_close: kill work thread [%d]\n", i);
	}

	uc_free(pTpool->thread_pool);
}

void 
uctp_do_job(void *pThreadPool, uctp_job pJob, void *pParam, int only_pool)
{
	uctp_main_s *pTpool = (uctp_main_s *)pThreadPool;
	uctp_thread_s *pThread = NULL;
	pthread_t thread_tmp;
	int i = 0;
	int ret = 0;

	if(pTpool == NULL) {
		uctp_err("uctp_do_job: entry pointer NULL\n");
		return;
	}

	while(only_pool > 0) {
		pthread_mutex_lock(&(pTpool->tp_lock));
		
		for(i=0; i < pTpool->thread_count; i++) {
			pThread = &(pTpool->thread_pool[i]);
			pthread_mutex_lock(&(pThread->thread_lock));
			if(pThread->is_busy <= 0) {
				uctp_debug("uctp_do_job: [%d] thread idle\n", i);
				pThread->is_busy = 1;
				pThread->pJob = pJob;
				pThread->pParam = pParam;
				pthread_mutex_unlock(&(pThread->thread_lock));
				uctp_debug("uctp_do_job: informing idle working thread [%d]\n", i);
				pthread_cond_signal(&(pThread->thread_cond));
				pthread_mutex_unlock(&(pTpool->tp_lock));
				return;
			}
			pthread_mutex_unlock(&(pThread->thread_lock));		
		}
		
		pthread_mutex_unlock(&(pTpool->tp_lock));

		uc_sleep(50);
	}

	ret = pthread_create(&thread_tmp, &(pTpool->th_attr), pJob, pParam);
	if(ret != 0){
		uctp_err("uctp_init: creat work thread failed\n");
		return;
	}
//	uctp_info("uctp_do_job: creat temp thread [0x%08X]\n", (unsigned int)thread_tmp);

	return;	
}

#ifdef __cplusplus
}
#endif

